/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package net.hands.ado.db.jdbc.dialect;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

/**
 * A dialect for Oracle 8i.
 * 
 * @author Steve Ebersole
 */
public class OracleDialect extends Dialect {
	private final SQLFunction FUNCTION = new OracleFunction();

	// private static final int PARAM_LIST_SIZE_LIMIT = 1000;

	public OracleDialect() {
		super();
		registerColumnType(Types.CHAR, "char(1 char)");
		registerColumnType(Types.VARCHAR, 4000, "varchar2($l char)");
		registerColumnType(Types.VARCHAR, "long");

		registerColumnType(Types.BIT, "number(1,0)");
		registerColumnType(Types.BIGINT, "number(19,0)");
		registerColumnType(Types.SMALLINT, "number(5,0)");
		registerColumnType(Types.TINYINT, "number(3,0)");
		registerColumnType(Types.INTEGER, "number(10,0)");
		registerColumnType(Types.FLOAT, "float");
		registerColumnType(Types.DOUBLE, "double precision");
		registerColumnType(Types.NUMERIC, "number($p,$s)");
		registerColumnType(Types.DECIMAL, "number($p,$s)");
		registerColumnType(Types.BOOLEAN, "number(1,0)");

		registerColumnType(Types.DATE, "date");
		registerColumnType(Types.TIME, "date");
		registerColumnType(Types.TIMESTAMP, "timestamp");

		registerColumnType(Types.BINARY, 2000, "raw($l)");
		registerColumnType(Types.BINARY, "long raw");
		registerColumnType(Types.VARBINARY, 2000, "raw($l)");
		registerColumnType(Types.VARBINARY, "long raw");
		registerColumnType(Types.BLOB, "blob");
		registerColumnType(Types.CLOB, "clob");
		registerColumnType(Types.LONGVARCHAR, "long");
		registerColumnType(Types.LONGVARBINARY, "long raw");

	}

	@Override
	public SQLFunction getFunction() {

		return FUNCTION;
	}

	@Override
	public Object getResultSetValue(final ResultSet rs, final int columnIndex)
			throws SQLException {
		Object obj = super.getResultSetValue(rs, columnIndex);
		if (obj != null) {
			final String className = obj.getClass().getName();
			if ("oracle.sql.TIMESTAMP".equals(className)
					|| "oracle.sql.TIMESTAMPTZ".equals(className)) {
				obj = rs.getTimestamp(columnIndex);
			} else if (className.startsWith("oracle.sql.DATE")) {
				final String metaDataClassName = rs.getMetaData()
						.getColumnClassName(columnIndex);
				if ("java.sql.Timestamp".equals(metaDataClassName)
						|| "oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
					obj = rs.getTimestamp(columnIndex);
				} else {
					obj = rs.getDate(columnIndex);
				}
			}
		}
		return obj;
	}

	@Override
	public String toLimitSQL(final String sql, final int i, final int fetchSize) {
		final StringBuilder sb = new StringBuilder();
		sb.append("select * from (select ROWNUM as rn, t_orcl.* from (")
				.append(sql).append(") t_orcl where ROWNUM <= ")
				.append(i + fetchSize).append(") where rn > ").append(i);
		return sb.toString();
	}
}
